﻿/******************************************************************
 *Company: http://www.xiaomutech.com/
 *fileName : %{Cpp:License:FileName} --- %{Cpp:License:ClassName}
 *Auth       : yhni (QQ:393320854)
 *Create    : 2022/9/15
 *Description   :
 *Histroy:
 *<Auth>    <Date>        <Ver>        <Content>
 *         2022/9/15
 *******************************************************************/
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qmusiclist.h"
#include "qmp3info.h"
#include "qtmenuwidget.h"

#include <QNetworkRequest>
#include <QNetworkReply>

#include <QJsonDocument>
#include <QJsonParseError>
#include <QJsonObject>
#include <QJsonArray>
#include <QDebug>

#include <QApplication>
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QMenu>
#include <QMessageBox>
#include <QTextCodec>
#include <QTextStream>
#include <QButtonGroup>
#include <QBoxLayout>

MainWindow::MainWindow(QWidget *parent)
    : QWidgetBase(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    initMenus();
    initTrayIcon();
    m_currentMusic = NULL;
    ui->widgetLocalList->setListMode(0x01);
    m_nCurrentPage = PageLocal;

    m_http = new QNetworkAccessManager(this);
    connect(m_http, &QNetworkAccessManager::finished, this, &MainWindow::sltNetworkFinish);

    m_download = new QHttpDownload(this);
    connect(m_download, &QHttpDownload::finished, this, &MainWindow::downloadFinished);
    connect(ui->widgetList, &QMusicList::download, this, &MainWindow::download);
    connect(ui->widgetList, &QMusicList::itemClicked, this, &MainWindow::itemClicked);
    connect(ui->widgetList, &QMusicList::musicChanged, this, &MainWindow::musicChanged);
    connect(ui->widgetLocalList, &QMusicList::itemClicked, this, &MainWindow::itemClicked);
    connect(ui->widgetLocalList, &QMusicList::musicChanged, this, &MainWindow::musicChanged);

    m_player = new QMediaPlayer(this);
    connect(m_player, &QMediaPlayer::durationChanged, this, &MainWindow::durationChanged);
    connect(m_player, &QMediaPlayer::positionChanged, this, &MainWindow::positionChanged);
    connect(m_player, &QMediaPlayer::stateChanged, this, &MainWindow::stateChanged);

    ui->widgetProgress->setHorizontal(true);
    QButtonGroup *btnGroup = new QButtonGroup(this);
    btnGroup->addButton(ui->btnLeftStat, 0);
    btnGroup->addButton(ui->btnLeftMusic, 1);
    btnGroup->addButton(ui->btnLeftVideo, 2);
    btnGroup->addButton(ui->btnLeftRadio, 3);
    btnGroup->addButton(ui->btnLeftLike, 4);
    btnGroup->addButton(ui->btnLeftLocal, 5);
    btnGroup->addButton(ui->btnLeftRecent, 6);
    btnGroup->addButton(ui->btnLeftMusiclist, 7);
    connect(btnGroup, SIGNAL(buttonClicked(int)), this, SLOT(sltLeftButtonClicked(int)));
    connect(ui->labelSingerHeader, &QClickLabel::clicked, this, &MainWindow::sltShowLyricPage);
    connect(ui->widgetProgress, &QtSliderBar::valueChanged, this, &MainWindow::sltProcessChanged);

    m_notify = new QtNotification(this);
    checkDirs();
    loadLocalMusics();
    showSingerPixmap(":/res/images/album.jpg");
}

MainWindow::~MainWindow()
{
    delete ui;
    ui->widgetLyric->closeDesktop();
}

void MainWindow::initMenus()
{
    QMenu *btnMenu = new QMenu(this);
    btnMenu->addAction(QStringLiteral("系统设置"))->setProperty("index", 0x0101);
    btnMenu->addAction(QStringLiteral("下载设置"))->setProperty("index", 0x0102);
    btnMenu->addSeparator();
    btnMenu->addAction(QStringLiteral("关于"))->setProperty("index", 0x0401);
    btnMenu->addAction(QStringLiteral("检查更新"))->setProperty("index", 0x0402);
    btnMenu->addAction(QStringLiteral("源代码"))->setProperty("index", 0x0403);

    QMenu *skinMenu = new QMenu(QStringLiteral("皮肤设置"), this);
    QActionGroup *skinGroup = new QActionGroup(this);
    QStringList strSkins = QStringList() << QStringLiteral("浅色") << QStringLiteral("深色") << QStringLiteral("自定义");
    for (int i = 0; i < strSkins.size(); i++)
    {
        QAction *_action = skinMenu->addAction(strSkins.at(i));
        _action->setProperty("index", 0x0301 + i);
        _action->setCheckable(true);
        _action->setChecked(0 == i);
        skinGroup->addAction(_action);
    }

    btnMenu->addMenu(skinMenu);
    connect(btnMenu, &QMenu::triggered, this, &MainWindow::sltSysMenuTrigger);
    ui->btnWinMenu->setMenu(btnMenu);

    // 清晰度
    QMenu *btnPlayMode = new QMenu(this);
    QActionGroup *modeGroup = new QActionGroup(this);
    QStringList videoLevels = QStringList() << QStringLiteral("顺序播放") << QStringLiteral("单曲播放") << QStringLiteral("单曲循环") << QStringLiteral("随机播放");
    for (int i = 0; i < videoLevels.size(); i++)
    {
        QAction *_action = btnPlayMode->addAction(videoLevels.at(i));
        _action->setProperty("mode", i);
        _action->setCheckable(true);
        _action->setChecked(2 == i);
        modeGroup->addAction(_action);
    }

    ui->btnPlayMode->setMenu(btnPlayMode);
    connect(btnPlayMode, &QMenu::triggered, this, &MainWindow::sltPlayModeChanged);

    QWidget *widgetMute = new QWidget(this);
    widgetMute->setObjectName("widgetMute");
    widgetMute->setFixedSize(55, 150);
    QtSliderBar *muteSlider = new QtSliderBar(this);
    muteSlider->setFixedSize(10, 100);
    muteSlider->setMaxmum(100);
    muteSlider->setValue(99);

    QLabel *labelMute = new QLabel(this);
    labelMute->setText(QString("100%"));
    connect(muteSlider, &QtSliderBar::valueChanged, this, [=](int value){
        labelMute->setText(QString("%1%").arg(value));
        m_player->setVolume(value);
    });

    QVBoxLayout *verLayout = new QVBoxLayout(widgetMute);
    verLayout->setContentsMargins(10, 10, 10, 10);
    verLayout->setSpacing(10);
    verLayout->addWidget(muteSlider, 1, Qt::AlignHCenter);
    verLayout->addWidget(labelMute);

    QtMenuWidget *muteMenu = new QtMenuWidget(widgetMute);
    muteMenu->setDireciton(QtMenuWidget::Bottom);
    muteMenu->installEventFilter(this);
    ui->btnMute->setMenu(muteMenu);
}
void MainWindow::initTrayIcon()
{
    QMenu *menu = new QMenu(this);
    int index = 0;
    menu->addAction("上 一 首")->setProperty("index", index++);
    menu->addAction("播放/暂停")->setProperty("index", index++);
    menu->addAction("下 一 首")->setProperty("index", index++);
    menu->addAction("退    出", qApp, SLOT(quit()))->setProperty("index", index++);

    m_sysTrayicon = new QSystemTrayIcon(this);
    m_sysTrayicon->setContextMenu(menu);
    m_sysTrayicon->setIcon(QIcon(":/res/images/ic_music.png"));
    connect(m_sysTrayicon , SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(onActivated(QSystemTrayIcon::ActivationReason)));
    m_sysTrayicon->show();
}

void MainWindow::sltNetworkFinish(QNetworkReply *_reply)
{
    if (QNetworkReply::NoError == _reply->error())
    {
        QByteArray byData = _reply->readAll();
        if (Search == m_nType)
        {
            parseSearch(byData);
        }
        else if (GetSong == m_nType)
        {
            parseGetsong(byData);
        }
        else if (Download == m_nType)
        {
            parseDownload(byData);
        }
    }
    else
    {
        qDebug() << "[http] reply error" << _reply->errorString() << m_nType;
        showNotify(QStringLiteral("网络错误:") + _reply->errorString(), QtNotifyItem::MsgWarin);
    }

    ui->widgetList->setWait(false);
    m_nType = None;
    qDebug() << "http request finish!";
}

void MainWindow::searchSong(const QString &_name)
{
    m_nType = Search;
    QString strUrl = QString("http://mobilecdn.kugou.com/api/v3/search/song?format=json&keyword=%1&page=1&pagesize=30").arg(_name);
    QNetworkRequest request;
    request.setUrl(strUrl);
    m_http->get(request);
}

void MainWindow::parseSearch(const QByteArray &_byData)
{
    QJsonObject docObj = getJsonObject(_byData);
    int errcode = docObj.value("errcode").toInt();
    if (0 != errcode || docObj.isEmpty())
    {
        qDebug() << "Search music failed";
        return;
    }

    QJsonObject jsonObj = docObj.value("data").toObject();
    QJsonArray jsonInfos = jsonObj.value("info").toArray();
    ui->widgetList->clear();

    for (int i = 0; i < jsonInfos.size(); i++)
    {
        QJsonObject songObj = jsonInfos.at(i).toObject();
        QMusicItem *_item = new QMusicItem(i);
        _item->setHash(songObj.value("hash").toString());
        _item->setSinger(songObj.value("singername").toString());
        _item->setAlbum(songObj.value("album_name").toString());
        _item->setAlbumId(songObj.value("album_id").toString());
        _item->setDuration(songObj.value("duration").toInt());
        _item->setSong(songObj.value("songname").toString());
        ui->widgetList->addItem(_item);

        qDebug() << _item->id() << _item->song() << _item->singer() << _item->album() << _item->durationTime();
    }

}

void MainWindow::auditionSong(const QString &_albumId, const QString &_hash)
{
    if (_hash.isEmpty()) return;

    m_nType = GetSong;
    QString strUrl = QString("https://www.kugou.com/yy/index.php?r=play/getdata&hash=%1&album_id=%2&_=1497972864535").arg(_hash).arg(_albumId);
    QNetworkRequest request;
    request.setUrl(strUrl);
    request.setRawHeader("Cookie", "kg_mid=233");
    m_http->get(request);
}

void MainWindow::download(const QString &_albumId, const QString &_hash)
{
    m_nType = Download;
    QString strUrl = QString("https://www.kugou.com/yy/index.php?r=play/getdata&hash=%1&album_id=%2&_=1497972864535").arg(_hash).arg(_albumId);
    QNetworkRequest request;
    request.setUrl(strUrl);
    request.setRawHeader("Cookie", "kg_mid=233");
    m_http->get(request);
}

void MainWindow::downloadFinished(const QString &_fileName)
{
    QFileInfo fileinfo(_fileName);
    if ("mp3" == fileinfo.suffix())
    {
        this->showNotify(QStringLiteral("[%1] 下载完成!~").arg(fileinfo.baseName()), QtNotifyItem::MsgOk);
    }
    else if ("jpg" == fileinfo.suffix())
    {
        showSingerPixmap(_fileName);
        showAlbumPixmap(_fileName);
    }
}

void MainWindow::showNotify(const QString &_msg, int _type)
{
    m_notify->setNotification(_msg, _type);
}

void MainWindow::parseGetsong(const QByteArray &_byData)
{
    QJsonObject docObj = getJsonObject(_byData);
    if (docObj.isEmpty())
    {
        qDebug() << "get song failed";
        return;
    }

    QJsonObject jsonObj = docObj.value("data").toObject();
    QString play_url    = jsonObj.value("play_url").toString();
    QString album_name  = jsonObj.value("album_name").toString();
    QString lyrics      = jsonObj.value("lyrics").toString();
    QString img         = jsonObj.value("img").toString();
    QString author      = jsonObj.value("author_name").toString();
    QString audio_name  = jsonObj.value("audio_name").toString();

    if (play_url.isEmpty())
    {
        this->showNotify(QStringLiteral("歌曲地址获取失败，请换其他歌!"), 0x02);
        return;
    }

    ui->labelSongName->setText(audio_name);
    ui->labelSinger->setText(author);

    if (!img.isEmpty())
    {
        m_download->download(img, audio_name + ".jpg", "authors");
    }

    if (NULL != m_currentMusic)
    {
        m_currentMusic->setPlayUrl(play_url);
        m_currentMusic->setImgUrl(img);
    }

    writeLyrics(audio_name, lyrics);
    playMusic(play_url, audio_name);
    qDebug() << "play network music:" << play_url;
}

void MainWindow::parseDownload(const QByteArray &_byData)
{
    QJsonObject docObj = getJsonObject(_byData);
    if (docObj.isEmpty())
    {
        qDebug() << "get song failed";
        return;
    }

    QJsonObject jsonObj = docObj.value("data").toObject();
    QString play_url    = jsonObj.value("play_url").toString();
    QString audio_name  = jsonObj.value("audio_name").toString();
    QString lyrics      = jsonObj.value("lyrics").toString();
    QString img         = jsonObj.value("img").toString();

    if (!play_url.isEmpty())
    {
        m_download->download(play_url, audio_name + ".mp3", "musics");
        m_download->download(img, audio_name + ".jpg", "authors");
    }

    if (!lyrics.isEmpty())
    {
    writeLyrics(audio_name, lyrics);
}
}

void MainWindow::writeLyrics(const QString &_song, const QString &_lyrics)
{
    QFile file(qApp->applicationDirPath() + "/lyrics/" + _song + ".lrc");
    if (file.open(QIODevice::ReadWrite))
    {
        file.write(_lyrics.toUtf8());
        file.close();
    }
}

void MainWindow::playMusic(const QString &_url, const QString &_name)
{
    if (QMediaPlayer::StoppedState != m_player->state())
    {
        m_player->stop();
    }
    ui->widgetLyric->setLyric(_name);
    m_player->setMedia(QUrl(_url));
    m_player->play();
    if (!_url.startsWith("http"))
    {
        QString _fileName = qApp->applicationDirPath() + "/authors/" + _name + ".jpg";
        showAlbumPixmap(_fileName);
        showSingerPixmap(_fileName);
    }
}

void MainWindow::playCurrentList()
{
    if (NULL == m_currentMusic) return;

    if (m_currentMusic->playUrl().isEmpty())
    {
        auditionSong(m_currentMusic->albumId(), m_currentMusic->hash());
    }
    else {
        QString audio_name = m_currentMusic->singer() + " - " + m_currentMusic->song();
        playMusic(m_currentMusic->playUrl(), audio_name);
        ui->labelSinger->setText(m_currentMusic->singer());
        ui->labelSongName->setText(audio_name);
    }
}

void MainWindow::resizeEvent(QResizeEvent *e)
{
    QRect _rect = QRect(0, ui->widgetTitle->height() + 5, this->width(), this->height());
    m_notify->setParentRect(_rect);
    QWidgetBase::resizeEvent(e);
}

bool MainWindow::eventFilter(QObject * obj, QEvent *event)
{
    if (event->type() == QEvent::Show && obj == ui->btnMute->menu())
    {
        QWidget *w = qobject_cast<QWidget*>(obj);
        QPoint p = ui->btnMute->mapToGlobal(QPoint(0, 0));
        p.setY(p.y() - w->height() - 10);
        p.setX(p.x() - w->width() * 0.5 + ui->btnMute->width() * 0.5);
        w->move(p);
        return true;
    }
    return false;
}

QJsonObject MainWindow::getJsonObject(const QByteArray &_byData)
{
    QJsonParseError jsonErr;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(_byData, &jsonErr);
    if (jsonErr.error != QJsonParseError::NoError)
    {
        qDebug() << "Pase json error" << jsonErr.errorString();
        return QJsonObject();
    }

    return jsonDoc.object();
}

void MainWindow::on_btnSearch_clicked()
{
    QString strSong = ui->lineEditSearch->text();
    ui->btnLeftMusiclist->setChecked(true);
    sltChangePage(PageSearch);
    ui->btnLyric->setChecked(false);
    if (strSong.isEmpty())
    {
        strSong = QStringLiteral("小城夏天");
    }

    ui->widgetList->setWait(true);
    searchSong(strSong);
}

void MainWindow::durationChanged(qint64 duration)
{
    ui->widgetProgress->setMaxmum(duration);
    duration /= 1000;
    ui->labelDuration->setText(QString("%1:%2").arg(duration / 60, 2, 10, QChar('0')).arg(duration % 60, 2, 10, QChar('0')));
}

void MainWindow::positionChanged(qint64 position)
{
    ui->widgetLyric->setPosition(position);
    ui->widgetProgress->setValue(position);
    if (position >= ui->widgetProgress->maximum())
    {
        ui->widgetLocalList->setNextIndex();
    }

    position /= 1000;
    ui->labelPostion->setText(QString("%1:%2").arg(position / 60, 2, 10, QChar('0')).arg(position % 60, 2, 10, QChar('0')));
}

void MainWindow::stateChanged(QMediaPlayer::State _state)
{
    if (QMediaPlayer::PlayingState == _state)
    {
        ui->btnPlay->setText(QChar(0xe7cb));
        ui->widgetLyric->setMediaState(true);
    }
    else if (QMediaPlayer::StoppedState == _state)
    {
        playCurrentList();
    }
    else {
        ui->btnPlay->setText(QChar(0xe7cd));
        ui->widgetLyric->setMediaState(false);
    }
}

void MainWindow::itemClicked(QAbstractListItem *_item)
{
    if (NULL == _item)
    {
        return;
    }

    m_currentMusic = qobject_cast<QMusicItem*>(_item);
}

void MainWindow::musicChanged(QMusicItem *_item)
{
    if (NULL == _item)
    {
        return;
    }

    m_currentMusic = _item;
    playCurrentList();
}

void MainWindow::on_btnLyric_clicked(bool checked)
{
    ui->widgetLyric->showDesktopLyric(checked);
}

void MainWindow::on_btnPrev_clicked()
{
    ui->widgetLocalList->setPrevIndex();
    playCurrentList();
}

void MainWindow::on_btnNext_clicked()
{
    ui->widgetLocalList->setNextIndex();
    playCurrentList();
}

void MainWindow::on_btnPlay_clicked()
{
    if ((QMediaPlayer::PlayingState == m_player->state()))
    {
        m_player->pause();
    }
    else {
        if (!m_player->media().isNull()){
            m_player->play();
        }
        else
        {
            if (NULL != m_currentMusic)
            {
                playCurrentList();
            }
            else {
                qDebug() << "Please select music";
                showNotify(QStringLiteral("请选择需要播放的音乐！~"), QtNotifyItem::MsgInfo);
            }
        }
    }
}

void MainWindow::on_btnBack_clicked()
{
    if (ui->btnLeftMusiclist->isChecked())
    {
        sltChangePage(PageSearch);
    }
    else {
        sltChangePage(PageLocal);
    }
}

void MainWindow::on_btnLoadMusic_clicked()
{
    ui->widgetLocalList->clear();
    loadLocalMusics();
}

void MainWindow::sltShowLyricPage()
{
    bool isShow = ui->stackedWidget->currentIndex() == PageLyric;
    int backPage = ui->btnLeftMusiclist->isChecked() ? PageSearch : PageLocal;
    sltChangePage(!isShow ? PageLyric : backPage);
}

void MainWindow::sltProcessChanged(int value)
{
    if (m_player->state() == QMediaPlayer::PlayingState)
    {
        m_player->setPosition(value);
    }
}

void MainWindow::sltLeftButtonClicked(int index)
{
    if (0x07 == index)
    {
        sltChangePage(PageSearch);
    }
    else if (0x05 == index)
    {
        sltChangePage(PageLocal);
    }
}

void MainWindow::sltChangePage(int index)
{
    ui->stackedWidget->setCurrentIndex(index);
}

void MainWindow::checkDirs()
{
    QStringList strDirs = QStringList() << "lyrics"   << "musics" << "authors";
    foreach(QString _path, strDirs)
    {
        QDir dir(qApp->applicationDirPath() + "/" + _path);
        if (!dir.exists())
        {
            dir.mkpath(qApp->applicationDirPath() + "/" + _path);
        }
    }
}

void MainWindow::loadLocalMusics()
{
    QString strPath = qApp->applicationDirPath() + "/musics";
    QDir dir(strPath);
    QFileInfoList files = dir.entryInfoList(QStringList() << "*.mp3", QDir::Files);
    for (int i = 0; i < files.size(); i++)
    {
        QFileInfo fileinfo = files.at(i);
        QMusicItem *_item = new QMusicItem(i);
        _item->setSize(fileinfo.size());
        _item->setPlayUrl(fileinfo.absoluteFilePath());
        QMp3Info::analyseMusic(fileinfo.absoluteFilePath(), _item);
        ui->widgetLocalList->addItem(_item);
    }

    sltChangePage(files.isEmpty() ? PageSearch : PageLocal);
    ui->widgetLocalList->setWait(false);
}

void MainWindow::showSingerPixmap(const QString &_fileName)
{
    QPixmap pixmap(_fileName);
    if (pixmap.isNull())
        pixmap.load(":/res/images/album.jpg");
    QSize _size = ui->labelSingerHeader->size();
    pixmap = pixmap.scaled(_size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    ui->labelSingerHeader->setPixmap(pixmap);
}

void MainWindow::showAlbumPixmap(const QString &_fileName)
{
    ui->widgetLyric->setAlbumPixmap(QImage(_fileName));
    }

void MainWindow::on_lineEditSearch_returnPressed()
{
    on_btnSearch_clicked();
}

void MainWindow::sltSysMenuTrigger(QAction *_action)
{
    int index = _action->property("index").toInt();
    if (0x0401 == index)
    {
        QString strMsg = QStringLiteral("<h2>关于</h2>");
        strMsg += QStringLiteral("<p>1、本程序网络接口为kugou提供的免费接口。</p>");
        strMsg += QStringLiteral("<p>2、程序启动默认加载本地文件[musics]。</p>");
        strMsg += QStringLiteral("<p>3、本程序可以在线直接听歌，也可下载。</p>");
        QMessageBox::information(this, "提示", strMsg);
    }
    else if (0x0402 == index)
    {
        QString strInfo;
        bool bOk = QHttpDownload::checkAppVersion(APP_NAME, APP_VERSION, strInfo);
        if (bOk)
        {
            if (QMessageBox::No == QMessageBox::question(NULL, QStringLiteral("程序更新"), QStringLiteral("检查到更新\n【%1】，\n是否立即下载?").arg(strInfo)))
            {
                return;
            }
        }

    }
    else if (0x0403 == index)
    {
        QString strMsg = QStringLiteral("<h2>源代码</h2>");
        strMsg += QStringLiteral("<p>1、本程序涉及的图标为<a href='https://www.iconfont.cn'>iconfont</a>。</p>");
        strMsg += QStringLiteral("<p>2、本程序全部开源，如果涉及违规，后果自行承担。</p>");
        strMsg += QStringLiteral("<p>3、【gitee】<a href='https://gitee.com/xiaoni_pj'>https://gitee.com/xiaoni_pj。</a></p>");
        QMessageBox::information(this, QStringLiteral("提示"), strMsg);
    }
    else if (0x0101 == index)
    {
        sltChangePage(PageConfig);
}
}

void MainWindow::sltPlayModeChanged(QAction *_action)
{
    int index = _action->property("mode").toInt();
    const QList<QChar> icons = QList<QChar>() << QChar(0xe68d) << QChar(0xe621) << QChar(0xe66d) << QChar(0xe71f);
    if (index < 0 || (index + 1) > icons.size())
    {
        return;
    }
    ui->btnPlayMode->setText(icons.at(index));
    ui->btnPlayMode->setProperty("mode", index);
}



// 激活系统托盘
void MainWindow::onActivated(QSystemTrayIcon::ActivationReason reason)
{
    switch(reason)
    {
    // 单击托盘显示窗口
    case QSystemTrayIcon::Trigger:
    {
        showNormal();
        raise();
        activateWindow();
        break;
    }
    // 双击
    case QSystemTrayIcon::DoubleClick:
    {
        // ...
        break;
    }
    default:
        break;
    }
}


